package com.t2t.top.devops.utils;

import lombok.Data;
import org.apache.commons.lang3.SystemUtils;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.math.BigDecimal;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * App服务信息.
 */
public class AppInfoUtils {

    private AppInfoUtils() {
    }

    public static Map info() {
        AppInfoBuilder builder = new AppInfoBuilder();
        //备注：采用LinkedHashMap主要方便顺序查看结果.
        Map<String, Object> info = new LinkedHashMap();
        info.put("app", builder.getAppInfo());
        info.put("runtime", builder.getRuntimeInfo());
        info.put("memory", builder.getMemoryInfo());
        info.put("os", builder.getOsInfo());
        return info;
    }

}

class AppInfoBuilder {

    /**
     * 备注：采用LinkedHashMap主要方便顺序查看结果.
     */
    public Map build() {
        Map<String, Object> info = new LinkedHashMap();
        info.put("app", getAppInfo());
        info.put("runtime", getRuntimeInfo());
        info.put("memory", getMemoryInfo());
        info.put("os", getOsInfo());
        return info;
    }

    public Map getAppInfo() {
        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        String name = runtime.getName();
        String pid = name.split("@")[0];

        Map basicInfo = new LinkedHashMap();
        basicInfo.put("version", VersionUtils.getInstance().getVersion());
        basicInfo.put("artifactId", VersionUtils.getInstance().getArtifactId());
        basicInfo.put("groupId", VersionUtils.getInstance().getGroupId());
        basicInfo.put("pid", pid);
        //basicInfo.put("ip", NetTools.getLocalAddress().getHostAddress());
        basicInfo.put("upTime", formatTimeHumanReadable(new Date(runtime.getUptime()).getTime()));
        basicInfo.put("startTime", DateUtils.format(new Date(runtime.getStartTime())));
        return basicInfo;
    }

    public RuntimeInfo getRuntimeInfo() {
        RuntimeInfo runtimeInfo = new RuntimeInfo();
        //系统属性
        Properties props = System.getProperties();
        runtimeInfo.setVmName(props.getProperty("java.vm.name"));
        runtimeInfo.setVmVendor(props.getProperty("java.vm.vendor"));
        runtimeInfo.setVmVer(props.getProperty("java.version"));
        runtimeInfo.setJdkVer(props.getProperty("java.vm.version"));
        runtimeInfo.setJdkClassVer(props.getProperty("java.class.version"));
        return runtimeInfo;
    }

    public MemoryInfo getMemoryInfo() {
        MemoryInfo memoryInfo = new MemoryInfo();
        memoryInfo.setFreeMemory(getMemoryValue(Runtime.getRuntime().freeMemory()));
        memoryInfo.setMaxMemory(getMemoryValue(Runtime.getRuntime().maxMemory()));
        memoryInfo.setTotalMemory(getMemoryValue(Runtime.getRuntime().totalMemory()));
        memoryInfo.setUsedMemory(getMemoryValue(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
        return memoryInfo;
    }

    public OsInfo getOsInfo() {
        OsInfo osInfo = new OsInfo();
        osInfo.setName(SystemUtils.OS_NAME);
        osInfo.setVer(SystemUtils.OS_VERSION);
        osInfo.setArch(SystemUtils.OS_ARCH);
        osInfo.setAvailableProcessors(Runtime.getRuntime().availableProcessors());
        osInfo.setSystemLoadAverage(ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage());
        return osInfo;
    }

    public String getMemoryValue(Long bit) {
        return get(1.0 * bit / 1024 / 1024) + " M";
    }

    public BigDecimal get(Double value) {
        return new BigDecimal(value).setScale(4, BigDecimal.ROUND_HALF_UP);
    }

    //参考linux中的h参数，人性化显示。表示"human-readable"，比较容易看清楚结果
    public String formatTimeHumanReadable(Long s) {
        //小时
        if (s >= 60 * 60 * 1000) {
            return chu(s, (60 * 60 * 1000), 2) + "小时";
        }
        //分钟
        if (s >= 60 * 1000) {
            return chu(s, (60 * 1000), 2) + "分钟";
        }
        //秒
        if (s >= 1000) {
            return chu(s, 1000, 2) + "秒";
        }
        return s + "毫秒";
    }

    public BigDecimal chu(Object s1, Object s2, Integer scale) {
        BigDecimal b1 = new BigDecimal(s1 + "");
        BigDecimal b2 = new BigDecimal(s2 + "");
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
    }

}

@Data
class MemoryInfo {

    //虚拟机内存总量
    private String totalMemory;
    //获取java虚拟机中的空闲内存量
    private String freeMemory;
    //获取java虚拟机试图使用的最大内存量
    private String maxMemory;

    private String usedMemory;

}

@Data
class RuntimeInfo {

    //Java的虚拟机实现版本
    private String vmVer;
    //Java的虚拟机实现名称
    private String vmVendor;
    //Java的虚拟机实现供应商
    private String vmName;

    //Java的运行环境版本
    private String jdkVer;
    //Java的类格式版本号
    private String jdkClassVer;

}

@Data
class OsInfo {

    //操作系统的名称
    private String name;

    //操作系统的构架
    private String arch;

    //操作系统的版本
    private String ver;

    //当前电脑CPU数量
    private Integer availableProcessors;

    //cpu负载
    private Double systemLoadAverage;

}